//go:generate go run generatedal.go

package main

import (
	"fmt"
	"github.com/iancoleman/strcase"
	"gopkg.in/yaml.v2"
	"gorm.io/driver/mysql"
	"gorm.io/gen"
	"gorm.io/gorm"
	"os"
	"strings"
)

// 定义一个配置的结构体 和Data结构体一样
type Config struct {
	Data struct {
		Database struct {
			Driver string `yaml:"driver"`
			Source string `yaml:"source"`
		} `yaml:"database"`
	} `yaml:"data"`
}

// 自定义查询的接口
type Querier interface {
	//select * from users u iner join orders o on u.id = o.user_id where u.id = ? and u.name = ?
	GetOrdersByUserIDAndName(userID int, name string) ([]*gen.T, error)
}

func main() {
	g := gen.NewGenerator(gen.Config{
		OutPath:      "../dal/query",
		Mode:         gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
		ModelPkgPath: "../dal/entity",
	})

	// 获取配置文件
	config, err := loadConfig()
	if err != nil {
		panic(err)
	}
	gormdb, _ := gorm.Open(mysql.Open(config.Data.Database.Source), &gorm.Config{})
	g.UseDB(gormdb) // reuse your gorm db

	var tables = []string{"users", "students"}
	tableModels := make([]interface{}, len(tables))
	//// Generate basic type-safe DAO API for struct `model.User` following conventions
	//给生成的模型都加上Mo后缀
	g.WithModelNameStrategy(func(tableName string) (modelName string) {
		//modelName后面加上Mo
		modelName = strcase.ToCamel(tableName) + "Mo"
		return modelName
	})
	//表都加上t_前缀
	g.WithTableNameStrategy(func(tableName string) (targetTableName string) {
		return "t_" + tableName
	})
	g.WithFileNameStrategy(func(tableName string) (fileName string) {
		return strings.TrimLeft(tableName, "t_")

	})
	//数据类型转换
	var dataMap = map[string]func(gorm.ColumnType) (dataType string){
		// int mapping
		"int": func(columnType gorm.ColumnType) (dataType string) {
			if n, ok := columnType.Nullable(); ok && n {
				return "*int32"
			}
			return "int32"
		},

		// bool mapping
		"tinyint": func(columnType gorm.ColumnType) (dataType string) {
			ct, _ := columnType.ColumnType()
			if strings.HasPrefix(ct, "tinyint(1)") {
				return "bool"
			}
			return "byte"
		},
		"timestamp": func(columnType gorm.ColumnType) (dataType string) {
			return "time.Time"
		},
	}
	g.WithDataTypeMap(dataMap)
	for i, table := range tables {
		tableModels[i] = g.GenerateModel(table)
	}
	//生成所有的数据表的结构体
	g.ApplyBasic(
		// Generate structs from all tables of current database
		tableModels...,
	)
	//复杂的查询生成器 注解 根据SQL生成方法
	g.ApplyInterface(func(Querier) {
	}, g.GenerateModel("users"))

	// Generate the code
	g.Execute()
}

func loadConfig() (Config, error) {
	file, err := os.Open("../../../configs/config.yaml")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	var config Config
	err = yaml.NewDecoder(file).Decode(&config)
	if err != nil {
		panic(err)
	}
	fmt.Println(config)
	return config, nil
}
